package ru.volgogradetzzz.display {
	import com.adobe.utils.AGALMiniAssembler;
	import com.adobe.utils.PerspectiveMatrix3D;
	import flash.display3D.Context3DCompareMode;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.VertexBuffer3D;
	import flash.utils.ByteArray;
	import ru.volgogradetzzz.geom.UVBox;
	import ru.volgogradetzzz.math.VMatrix2D;
	import ru.volgogradetzzz.math.VVector2;
	/**
	 * ...
	 * @author Volgogradetzzz
	 */
	public class Stage2D extends Main3D {
		
		public const ALL_COLORS:Vector.<Number> = new Vector.<Number>();
		public const ALL_INDICES:Vector.<uint> = new Vector.<uint>();
		public const ALL_UVS:Vector.<Number> = new Vector.<Number>();
		public const ALL_VERTICES:Vector.<Number> = new Vector.<Number>();
		
		private const _PROJECTION_MATRIX:PerspectiveMatrix3D = new PerspectiveMatrix3D();
		
		private var _firstChild:DisplayObject2D;
		private var _lastChild:DisplayObject2D;
		private var _totalDescendants:uint = 0;
		
		private var _vertexBuffer:VertexBuffer3D;
		private var _colorsBuffer:VertexBuffer3D;
		private var _uvsBuffer:VertexBuffer3D;
		private var _indexBuffer:IndexBuffer3D;
		
		public var verticesChanged:Boolean = true;
		public var colorsChanged:Boolean = true;
		public var uvsChanged:Boolean = true;
		public var indicesChanged:Boolean = true;
		
		private var _useColors:Boolean = true;
		private var _useTexture:Boolean = false;
		
		override protected function main():void {
			super.main();
			
			useColors();
			
			_PROJECTION_MATRIX.orthoOffCenterLH(0, 800, 600, 0, 1, 1000);
			setVertexMatrixConstant(0, _PROJECTION_MATRIX, true);
			
			setDepthTest(false, Context3DCompareMode.ALWAYS);
		}
		
		override protected function draw():void {
			updateData();
			
			if (ALL_VERTICES.length > 0) {
				if(verticesChanged) {
					_vertexBuffer = setVertexData(ALL_VERTICES, 3);
					verticesChanged = false;
					setVertexBuffer(0, _vertexBuffer, Context3DVertexBufferFormat.FLOAT_3);
				}
				
				if (colorsChanged && _useColors) {
					_colorsBuffer = setVertexData(ALL_COLORS, 3);
					colorsChanged = false;
					setVertexBuffer(1, _colorsBuffer, Context3DVertexBufferFormat.FLOAT_3);
				}
				
				if (uvsChanged && _useTexture) {
					_uvsBuffer = setVertexData(ALL_UVS, 2);
					uvsChanged = false;
					setVertexBuffer(2, _uvsBuffer, Context3DVertexBufferFormat.FLOAT_2);
				}
				
				if (indicesChanged) {
					_indexBuffer = setIndexData(ALL_INDICES);
					indicesChanged = false;
				}
				
				drawTriangles(_indexBuffer);
			}
		}
		
		public function addChild2D(child:DisplayObject2D):void {
			if (_firstChild == null) {
				_firstChild = child;
			}else {
				_lastChild.next = child;
				child.prev = _lastChild;
			}
			
			child.stage = this;
			
			_lastChild = child;
			
			_totalDescendants++;
			_totalDescendants += child.totalDescendants;
			
			child.updateIndex();
			
			child.addData();
		}
		
		public function removeChild2D(child:DisplayObject2D):void {
			
		}
		
		public function removeChildren2D():void {
			
		}
		
		public function updateData():void {
			var child:DisplayObject2D = _firstChild;
			while (child != null) {
				child.updateData();
				child = child.next;
			}
		}
		
		public function set totalDescendants(value:uint):void {
			_totalDescendants = value;
		}
		
		public function get totalDescendants():uint {
			return _totalDescendants;
		}
		
		public function useColors():void {
			_useColors = true;
			_useTexture = false;
			
			var vertexShaderString:String =
				'm44 op va0 vc0\n' +
				'mov v0 va1';
			
			var fragmentShaderString:String = 
				'mov oc, v0';
			
			var assembler:AGALMiniAssembler = new AGALMiniAssembler();
			var vertexShader:ByteArray = assembler.assemble(Context3DProgramType.VERTEX, vertexShaderString);
			var fragmentShader:ByteArray = assembler.assemble(Context3DProgramType.FRAGMENT, fragmentShaderString);
			
			setShaders(vertexShader, fragmentShader);
		}
		
		public function useTexture():void {
			_useColors = false;
			_useTexture = true;
			
			var vertexShaderString:String =
				'm44 op va0 vc0\n' +
				'mov v0 va2';
			
			var fragmentShaderString:String = 
				'tex oc, v0, fs0 <2d,linear,nomip>';
			
			var assembler:AGALMiniAssembler = new AGALMiniAssembler();
			var vertexShader:ByteArray = assembler.assemble(Context3DProgramType.VERTEX, vertexShaderString);
			var fragmentShader:ByteArray = assembler.assemble(Context3DProgramType.FRAGMENT, fragmentShaderString);
			
			setShaders(vertexShader, fragmentShader);
		}
	}
}